package sys;

import java.util.*;
import java.util.concurrent.*;
import java.io.*;
import java.sql.*;

import sys.fsm.*;
import sys.transport.*;
import sys.logic.*;
import sys.message.*;
import sys.database.*;
import org.json.*;
import sys.utils.*;
import sys.decision.*;

public class RequestManager
{
    public RequestManager(String confFilePath)
    {
        readParams(confFilePath);
        
        ms = new MessageSenderSMTP(mailserver, portSMTP);

        db = new DBWrapper(DBServer, DB, DBUser, DBPass);
        db.connect();

        try { nextRequestNumber = SysbDatabase.maxRequestID(DBServer, DB, DBUser, DBPass) + 1; }
        catch(Exception e) { System.out.println("Error when retrieving MAX(ID) : " + e.getMessage()); };

        requests = new Hashtable<Integer, Automat>();
        messages = new ConcurrentLinkedQueue<UniMessage>();
    }

    private void readParams(String confFilePath)
    {
        File confFile = new File(confFilePath);
        String conf = ReadWriteTextFile.getContents(confFile);

        try
        {
            JSONObject jo = new JSONObject(conf);

            mailserver = jo.getString("mailserver");
            portSMTP = jo.getString("smtpport");
            portPOP3 = jo.getString("pop3port");
            maillogin = jo.getString("maillogin");
            mailpass = jo.getString("mailpass");

            DBServer = jo.getString("DBServer");
            DB = jo.getString("DB");
            DBUser = jo.getString("DBUser");
            DBPass = jo.getString("DBPass");

            automatConfFilePath = jo.getString("automatConfFilePath"); 

            mailboxCheckingInterval = jo.getInt("mailboxCheckingInterval");

            decision = new DecisionSubsystem(jo.getInt("AllNetTeachingLevel"), jo.getInt("OneNodeTeachingLevel"));
        }
        catch(JSONException e)
        {
            System.out.println("Receiver : Error while parsing config file : " + e.getMessage());
        }

    }

    public void start()
    {
        MessageReceiver mr = new MessageReceiverPOP3(mailserver, portPOP3, maillogin, mailpass);
        MessageCheckerClient mcc = new MailsEntryPoint();
        mc = new MessageChecker(mr, mcc, mailboxCheckingInterval);
        mc.start();
        dojob = new DoJob();
        dojob.start();
    }

    public void stop()
    {
        decision.destroy();
        mc.stop();
        dojob.stop();
    }

    class DoJob extends Thread
    {
        public void run()
        {
            while(true)
            {
                for (UniMessage m : messages)
                {
                    System.out.println("FROM: " + m.getFrom() + ", TO: " + m.getTo() + ", BODY: " + m.getBody());
                
                    String type = null;
                    try
                    {
                        type = m.getString("Type");
                    }
                    catch(Exception e)
                    {
                        System.out.println("Error when retrieving field 'Type' : " + e.getMessage());
                        messages.remove(m);
                        continue;
                    }

                    if (type.compareTo("newRequest") == 0)
                    {
                        System.out.println("New request from Buyer");

                        try
                        {
                            long IDOnBuyer = m.getInt("ID");
                            String PSAddress = m.getString("PayingSystem");
                            String BuyerAddress = m.getFrom();
                            String userName = m.getString("UserName");
                            int quantity = m.getInt("Quantity");

                            ResultSet rs = db.select("Request", "IDOnBuyer = " + IDOnBuyer + " AND Buyer_Address = '" + 
                                                    BuyerAddress + "' AND User_Name = '" + userName + "'");
                            if (rs.next() == false)
                            {
                                rs = db.select("Request", "Buyer_Address = '" + BuyerAddress + "' AND User_Name = '" + userName + "'"); // есть ли такой пользователь?
                                if (rs.next() == false) // Нет - добавляем
                                { 
                                    System.out.println("Adding new user and making new neuronet for it");
                                    decision.newUser(BuyerAddress, userName, "prolog/prolog5.pl");
                                }

                                if (decision.decide(BuyerAddress, userName, quantity, 80) == 1) // Заявка одобрена
                                {
                                    System.out.println("Request is acked");
                                    requests.put(nextRequestNumber, new Automat(0, automatConfFilePath, decision)); 
                                    requests.get(nextRequestNumber).start_Message(nextRequestNumber, IDOnBuyer, PSAddress, BuyerAddress, userName, quantity);
                                    nextRequestNumber++;
                                }
                                else // Заявка отклонена
                                {
                                    System.out.println("Request is nacked");
                                    try
                                    {
                                        JSONMessage mes = new JSONMessage(maillogin+"@"+mailserver, BuyerAddress, "Ack granted");
                                        mes.put("Type", "nackSeller1");
                                        mes.put("nackOn", IDOnBuyer);
                                        ms.send(mes);
                                    }
                                    catch(Exception e)
                                    {
                                        System.out.println("Error while making JSONMessage or sending message in newRequest");
                                    }
                                }
                            }
                            else
                            {
                                try
                                {
                                    JSONMessage mes = new JSONMessage(maillogin+"@"+mailserver, BuyerAddress, "Ack granted");
                                    mes.put("Type", "ackSeller1");
                                    mes.put("ackOn", IDOnBuyer);
                                    ms.send(mes);
                                }
                                catch(Exception e)
                                {
                                    System.out.println("Error while making JSONMessage or sending message in newRequest");
                                }
                            }
                        }
                        catch(Exception e) {System.out.println("Error when processing 'NewRequest' : " + e.getMessage());};
                    }
                    else if (type.compareTo("ackPayingSystem") == 0)
                    {
                        System.out.println("Ack from Paying system");

                        try
                        {
                            int ackOnId = m.getInt("ackOn");

                            try { requests.get(ackOnId).ack_PayingSystem_1_Message(); }
                            catch(Exception e) { System.out.println("Error : " + e.getMessage()); }
                        }
                        catch(Exception e) {System.out.println("Error when retrieving fields from 'ackPayingSystem1' : " + e.getMessage());};
                    }
                    else if (type.compareTo("ackBuyer") == 0)
                    {
                        System.out.println("Ack from buyer");

                        try
                        {
                            int ackOnId = m.getInt("ackOn");
                            String userName = m.getString("User");
                            String BuyerAddress = m.getFrom();

                            ResultSet rs = db.select("Request", "IDOnBuyer = " + ackOnId + " AND Buyer_Address = '" + m.getFrom() + "' AND User_Name = '" + userName + "'");
                            boolean flag = rs.next();
                            if (flag && rs.getInt("AckByBuyer") == 0)
                            {
                                System.out.println("AckerByBuyer. Request number " + rs.getInt("ID"));
                                try { requests.get(rs.getInt("ID")).ack_Buyer_1_Message(); }
                                catch(Exception e) { System.out.println("Error : " + e.getMessage()); }
                            }
                            else if (flag)
                            {
                                try
                                {
                                    JSONMessage mes = new JSONMessage(maillogin+"@"+mailserver, BuyerAddress, "Ack on ack");
                                    mes.put("Type", "ackSeller2");
                                    mes.put("ackOn", ackOnId);
                                    ms.send(mes);
                                }
                                catch(Exception e)
                                {
                                    System.out.println("Error while making JSONMessage or sending message");
                                }
                            }
                        }
                        catch(Exception e) {System.out.println("Error when retrieving fields from 'ackBuyer' : " + e.getMessage());};
                    }
                    else if (type.compareTo("nackBuyer") == 0)
                    {
                        System.out.println("Nack from buyer");

                        try
                        {
                            int nackOnId = m.getInt("nackOn");
                            String BuyerAddress = m.getFrom();

                            System.out.println(requests.get(nackOnId));
                            try { requests.get(nackOnId).nack_Buyer_1_Message(); }
                            catch(Exception e) { System.out.println("Error : " + e.getMessage()); }
                        }
                        catch(Exception e) {System.out.println("Error when retrieving fields from 'ackBuyer' : " + e.getMessage());};
                    }
                    messages.remove(m);
                } 
                try
                {
                    //System.out.println("sleeping");
                    Thread.sleep(100);
                }
                catch(Exception e) {};
            }
        }
    }

    class MailsEntryPoint implements MessageCheckerClient
    {
        public void newMessages(ConcurrentLinkedQueue<UniMessage> messagesNew)
        {
            System.out.println("Systemb have got " + messagesNew.size() + " messages");
            messages.addAll(messagesNew);
        }
    }

    // Parametrs
    private String mailserver, maillogin, mailpass, portSMTP, portPOP3;
    private String DBServer, DB, DBUser, DBPass;
    private long mailboxCheckingInterval;
    private String automatConfFilePath;

    private DBWrapper db;
    private MessageChecker mc;
    private MessageSender ms;
    private Hashtable<Integer, Automat> requests;
    private int nextRequestNumber;

    private DecisionSubsystem decision;
    private ConcurrentLinkedQueue<UniMessage> messages;
    private Thread dojob;
}
